/*
 * Copyright (c) 2010, Nikolaus Moll
 * All rights reserved.
 */
package net.miblounge.gradecalculator.core.student;

import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import net.miblounge.gradecalculator.core.descriptors.courses.CourseDescription;
import net.miblounge.gradecalculator.core.serialization.GradeAdapter;

@XmlRootElement(namespace = "http://gradecalculator.net/")
@XmlType( 
 propOrder = { "courseIdentifier", "examNumber", "grades", "ungradedPassed", "courseDescription", "semester" } 
) 
public class ExaminationResult {

	private String courseIdentifier = "";
	private int examNumber = 0;
	private Map<ExaminationResultType, String>grades = new HashMap<ExaminationResultType, String>();
	private boolean ungradedPassed;
	private boolean isEstimated;
	private int semester;

	private CourseDescription courseDescription = null;
	
	private int hashCode = 0;
	
	public ExaminationResult()
	{
		this(0, "");
	}

	public ExaminationResult(final String courseIdentifier)
	{
		this(0, courseIdentifier);
	}

	public ExaminationResult(final int examNumber, final String courseIdentifier)
	{
		this.examNumber = examNumber;
		this.courseIdentifier = courseIdentifier;
	}

	@XmlTransient 
	public boolean isEstimated() {
		return isEstimated;
	}
	public void setEstimated(final boolean isEstimated) {
		this.isEstimated = isEstimated;
	}

	@XmlElement(name = "ungradedpassed") 
	public boolean getUngradedPassed() {
		return ungradedPassed;
	}
	public void setUngradedPassed(final boolean ungradedPassed) {
		this.hashCode = 0;
		this.ungradedPassed = ungradedPassed;
	}
	
	@XmlElement(name = "grades") 
	@XmlJavaTypeAdapter(GradeAdapter.class)
	public Map<ExaminationResultType, String> getGrades() {
		return grades;
	}
	public void setGrades(final Map<ExaminationResultType, String> grades) {
		this.hashCode = 0;
		this.grades = grades;
		
		// check
		// make isEstimated
		
		if ((grades.containsKey(ExaminationResultType.PASSED.getName())) &&
				(grades.size() == 1)) {
			isEstimated = false;
		} else {
			isEstimated = true;
		}
	}

	public String getGrade(final ExaminationResultType type) {
		if (grades.containsKey(ExaminationResultType.PASSED)) {
			return grades.get(ExaminationResultType.PASSED);
		}

		if (grades.containsKey(type)) {
			return grades.get(type);
		}
		
		return "";
	}
	public void setGrade(final ExaminationResultType type, final String grade) {
		this.hashCode = 0;

		if (type == ExaminationResultType.PASSED) {
			this.grades.clear();
			isEstimated = false;
		} else {
			isEstimated = true;
			if (this.grades.containsKey(ExaminationResultType.PASSED)) {
				this.grades.remove(ExaminationResultType.PASSED);
			}
		}
		
		if (grade.equals("")) {
			if (grades.containsKey(type)) {
				grades.remove(type);
			}
		} else {
			grades.put(type, grade);
		}
	}
	
	public boolean getUngradedPassed(final ExaminationResultType type) {
		if (type != ExaminationResultType.PASSED) {
			return true;
		}
		return getUngradedPassed();
	}

	public void setUngradedPassed(final ExaminationResultType type, final boolean passed) {
		if (type != ExaminationResultType.PASSED) {
			return;
		}
		setUngradedPassed(passed);
	}

	@XmlElement(name = "courseidentifier") 
	public String getCourseIdentifier() {
		return courseIdentifier;
	}
	public void setCourseIdentifier(final String courseIdentifier) {
		this.courseIdentifier = courseIdentifier;
	}

	@XmlElement(name = "examnumber") 
	public int getExamNumber() {
		return examNumber;
	}
	public void setExamNumber(final int examNumber) {
		this.examNumber = examNumber;
	}

	@XmlElement(name = "coursedescription") 
	public CourseDescription getCourseDescription() {
		return courseDescription;
	}
	public void setCourseDescription(final CourseDescription courseDescription) {
		this.courseDescription = courseDescription;
	}
	
	@XmlElement(name = "semester") 
	public int getSemester() {
		return semester;
	}
	public void setSemester(final int semester) {
		this.semester = semester;
	}


	@Override
	public int hashCode() {
		int result = hashCode;
		if (result == 0) {
			result = 17;
			result = 31 * result + grades.hashCode(); // check if this is enough
			result = 31 * result + (ungradedPassed ? 1 : 0);
			result = 31 * result + semester;
			result = 31 * result + courseIdentifier.hashCode();
		}
		return result;
	}


	public String toString()
	{
		return "ExaminationResult[" + courseIdentifier + "]" + super.toString(); 
	}

}
